package main.math;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

import main.entity.Hero;
import main.entity.LeveledHero;
import main.entity.Skill;

public class Calculator {

	public static LeveledHero getHeroAt(Hero h, int level) {
		LeveledHero retorno = new LeveledHero();
		retorno.setLevel(level);

		BigDecimal initialGold = h.getInitialGold();

		BigDecimal goldForLevel = getGoldForLevel(initialGold, level);
		retorno.setLevelGoldCost(goldForLevel);

		BigDecimal goldTilLevel = getTotalGoldTilLevel(initialGold, level);
		retorno.setTotalGoldCost(goldTilLevel);

		BigDecimal totalDps = getDPS(h, level);
		retorno.setTotalDPS(totalDps);

		return retorno;
	}

	public static BigDecimal getDPS(Hero h, int level) {
		BigDecimal retorno = new BigDecimal("0");
		BigDecimal totalMutiplier = new BigDecimal("1");

		BigDecimal initialDps = h.getInitialDPS();
		BigDecimal times = new BigDecimal(level);

		retorno = initialDps.multiply(times);

		BigDecimal skillMultiplier = getSkillMultiplier(h
				.getSkillsBefore(level));
		BigDecimal levelMultiplier = getLevelMultiplier(level);

		if (skillMultiplier != null) {
			totalMutiplier = totalMutiplier.add(skillMultiplier);
		}
		if (levelMultiplier != null) {
			totalMutiplier = totalMutiplier.add(levelMultiplier);
		}

		retorno = retorno.multiply(totalMutiplier);

		return retorno;
	}

	public static BigDecimal getLevelMultiplier(int level) {
		BigDecimal dec = new BigDecimal(level);
		BigDecimal step1 = new BigDecimal("25");
		BigDecimal step2 = new BigDecimal("1000");

		BigDecimal retorno = new BigDecimal("0");

		if (level >= 200) {
			
			BigDecimal expo = dec.divide(step1).setScale(0, RoundingMode.DOWN)
					.subtract(BigDecimal.valueOf(7));
			
			BigDecimal temp = BigDecimal.valueOf(4).pow(expo.intValue());
			
			retorno = retorno.add(temp);
		}
		
		if (level>=1000) {
			BigDecimal expo = dec.divide(step2).setScale(0, RoundingMode.DOWN);
			
			BigDecimal temp = BigDecimal.valueOf(2.5).pow(expo.intValue());
			
			retorno = retorno.multiply(temp).setScale(0, RoundingMode.DOWN);
			
		}
		return retorno;
	}

	public static BigDecimal getSkillMultiplier(Skill[] skillsBefore) {
		BigDecimal sum = new BigDecimal("0");

		if (skillsBefore != null && skillsBefore.length > 0) {

			for (Skill skill : skillsBefore) {
				sum = sum.add(BigDecimal.valueOf(skill.getSkillMultiplier()));
			}

		}

		return sum;
	}

	public static BigDecimal getGoldForLevel(BigDecimal initialGold, int level) {
		BigDecimal step = new BigDecimal("1.07");

		BigDecimal gold = new BigDecimal("0");
		gold = gold.add(initialGold.multiply(step.pow(level - 1)));
		gold = gold.setScale(0, RoundingMode.DOWN);

		return gold;
	}

	public static BigDecimal getTotalGoldTilLevel(BigDecimal initialGold,
			int level) {
		BigDecimal gold = new BigDecimal("0");

		for (int i = 1; i <= level; i++) {
			gold = gold.add(getGoldForLevel(initialGold, i));
		}
		gold = gold.setScale(0, RoundingMode.DOWN);

		return gold;
	}
	
	public static BigDecimal getInitialDPS(BigDecimal initialGold, int level) {
		BigDecimal retorno = new BigDecimal("0");
		BigDecimal N = BigDecimal.valueOf(level);
		
		BigDecimal min = null;
		
		if (level<14) {
			min = N;
		} else {
			min = BigDecimal.valueOf(14);
		}
		
		BigDecimal expo = new BigDecimal("0.0188").multiply(min);
		expo = BigDecimal.valueOf(1).subtract(expo);
		expo = expo.pow(N.intValue());
		
		retorno = initialGold.divide(BigDecimal.valueOf(10)).multiply(expo);

		return retorno.setScale(0, RoundingMode.UP);
	}
	
	
}
